package graphics;

import java.util.ArrayList;

import javax.media.opengl.GL;

import physics.GameObject;

import common.IParse;
import common.Point3D;
import common.Position3D;



public class GraphicalObject implements IParse{
	
	protected String name = null;
	protected Position3D position = new Position3D();
	protected double scale = 1;
    protected boolean isInitialized = false; 

	protected GameObject phyObj;

	protected ArrayList<GraphicalObject> components = new ArrayList<GraphicalObject>();

	
	protected float materialDiffuse[] = 	{ 1.0f, 1.0f, 1.0f, 1.0f };
	protected float materialAmbient[] = 	{ 0.2f, 0.2f, 0.2f, 1.0f };
	protected float materialSpecular[] = 	{ 0.0f, 0.0f, 0.0f, 1.0f };
	protected float materialEmission[] = 	{ 0.0f,	0.0f, 0.0f, 1.0f };

	protected boolean hasDiffuse = false;
	protected boolean hasAmbient = false;
	protected boolean hasSpecular = false;
	protected boolean hasEmission = false;
	
	protected float constatColor[] = 	{ 0.0f,	1.0f, 1.0f, 1.0f };
	protected boolean hasConstatColor = false;
	
	public GraphicalObject(){}
	

	public GraphicalObject(Position3D position){
		this.position = position;
	}

	public void setParameter(String name, String params[]){
		
		if (name.equals("scale")){
			this.scale = Double.parseDouble(params[0]);
			return;
		}
		
		if (name.equals("center")) {
			this.getPosition().move(Double.parseDouble(params[0]),
					Double.parseDouble(params[1]), Double.parseDouble(params[2]));
			return;
		}
		if (name.equals("rotate")) {
			double ax = Double.parseDouble(params[0]) / 180 * Math.PI;
			double ay = Double.parseDouble(params[1]) / 180 * Math.PI;
			double az = Double.parseDouble(params[2]) / 180 * Math.PI;
			this.getPosition().rotate(ax,ay,az);
			return;
		}
		if (name.equals("ambient")){
			materialAmbient[0] = Float.parseFloat(params[0]);
			materialAmbient[1] = Float.parseFloat(params[1]);
			materialAmbient[2] = Float.parseFloat(params[2]);
			hasAmbient = true;
			return;
		}

		if (name.equals("diffuse")){
			materialDiffuse[0] = Float.parseFloat(params[0]);
			materialDiffuse[1] = Float.parseFloat(params[1]);
			materialDiffuse[2] = Float.parseFloat(params[2]);
			hasDiffuse = true;
			return;
		}
		if (name.equals("specular")){
			materialSpecular[0] = Float.parseFloat(params[0]);
			materialSpecular[1] = Float.parseFloat(params[1]);
			materialSpecular[2] = Float.parseFloat(params[2]);
			hasSpecular = true;
			return;
		}
		if (name.equals("emission")){
			materialEmission[0] = Float.parseFloat(params[0]);
			materialEmission[1] = Float.parseFloat(params[1]);
			materialEmission[2] = Float.parseFloat(params[2]);
			hasEmission = true;
			return;
		}

		if (name.equals("constantColor")){
			constatColor[0] = Float.parseFloat(params[0]);
			constatColor[1] = Float.parseFloat(params[1]);
			constatColor[2] = Float.parseFloat(params[2]);
			hasConstatColor = true;
			return;
		}

	}
	public void commit(){};
	
	
	public void initialize(GL gl) {
		if (isInitialized) return;
		for(GraphicalObject gObj: components)
			gObj.initialize(gl);
		isInitialized = true;
	}
	

	private static void glMultMatrix(GL gl, GraphicalObject object) {
		double[] transform = {
				object.getPosition().getLeft().x,	object.getPosition().getLeft().y,	object.getPosition().getLeft().z,	0, 
				object.getPosition().getUp().x,	object.getPosition().getUp().y,	object.getPosition().getUp().z,	0,
				object.getPosition().getFace().x,	object.getPosition().getFace().y,	object.getPosition().getFace().z,	0,
				object.getPosition().getCenter().x,object.getPosition().getCenter().y,object.getPosition().getCenter().z	,1}; 
		gl.glMultMatrixd(transform,0);
		gl.glScaled(object.getScale(), object.getScale(), object.getScale());
	}
	
	protected void prerenderComponent(GL gl, GraphicalObject object){
		gl.glPushMatrix();
		glMultMatrix(gl, object);
		object.prerender(gl);
		gl.glPopMatrix();
	}

	protected void renderComponent(GL gl, GraphicalObject object){
		gl.glPushMatrix();
		glMultMatrix(gl, object);
		object.render(gl);
		gl.glPopMatrix();
	}

	protected void postrenderComponent(GL gl, GraphicalObject object){
		gl.glPushMatrix();
		glMultMatrix(gl, object);
		object.postrender(gl);
		gl.glPopMatrix();
	}

	public void addObject(GraphicalObject object3d){
		components.add(object3d);
	}

	public void removeObject(GraphicalObject object3d){
		components.remove(object3d);
	}
	
	public void prerender(GL gl){
//		try{
			for ( GraphicalObject object3D : components){
				prerenderComponent(gl, object3D);
			}
	//	}
//		catch (Exception e)
//		{
//			System.out.println("error [prerender]");
//		}
	}
	
	public void render(GL gl){

		if (hasConstatColor){
			gl.glColor3f(constatColor[0], constatColor[1], constatColor[2]);
		}
		
		for ( GraphicalObject object3D : components){
			renderComponent(gl, object3D);
		}

	}
	public void postrender(GL gl){
		for ( GraphicalObject object3D : components){
			postrenderComponent(gl, object3D);
		}
	}
	
	public Position3D getPosition() {
		return position;
	}

	public void setPosition(Position3D position) {
		this.position = position;
	}
	public GameObject getPhysicalObj() {
		return phyObj;
	}

	public void setPhysicalObj(GameObject phyObj) {
		this.phyObj = phyObj;
		this.position = phyObj.getPosition();
	}

	public ArrayList<GraphicalObject> getComponents() {
		return components;
	}

	public void setComponents(ArrayList<GraphicalObject> components) {
		this.components = components;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	public Point3D getCenter() {
		return position.getCenter();
	}

	public void setCenter(Point3D center) {
		this.position.setCenter(center);
	}

	public Point3D getFace() {
		return position.getFace();
	}

	public void setFace(Point3D face) {
		this.position.setFace(face);
	}

	public Point3D getUp() {
		return position.getUp();
	}

	public void setUp(Point3D up) {
		this.position.setUp(up);
	}

	public Point3D getLeft() {
		return position.getLeft();
	}

	public void setLeft(Point3D left) {
		this.position.setLeft(left);
	}

	public void move(double x, double y, double z){
		this.position.move(x, y, z);
	}
	
	public void rotate(double ax, double ay, double az) {
		position.rotate(ax, ay, az);
	}

	public double getScale() {
		return scale;
	}

	public void setScale(double scale) {
		this.scale = scale;
	}
 
	
	public static void render(GL gl, GraphicalObject object){
		gl.glPushMatrix();
		glMultMatrix(gl, object);
		object.render(gl);
		gl.glPopMatrix();
	
	}
	public static void prerender(GL gl, GraphicalObject object){
		gl.glPushMatrix();
		glMultMatrix(gl, object);
		object.prerender(gl);
		gl.glPopMatrix();
		
	}
	public static void postrender(GL gl, GraphicalObject object){
		gl.glPushMatrix();
		glMultMatrix(gl, object);
		object.postrender(gl);
		gl.glPopMatrix();
		
	}

}